{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f04dd603-a2d1-48ce-8c17-9f1dba8de1ee",
   "metadata": {},
   "source": [
    "Chapter 10\n",
    "\n",
    "# 一元多项式回归\n",
    "《线性代数》 | 鸢尾花书：数学不难"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccafb456-2453-4c82-8a65-b1963a370cb2",
   "metadata": {},
   "source": [
    "这段代码完整地实现了**一元三次多项式回归**的建模、拟合、预测和可视化过程。下面我们从数学角度详细描述这段代码背后在做什么，并结合公式帮助理解。\n",
    "\n",
    "---\n",
    "\n",
    "首先，代码使用 `numpy` 构造了一个二维数据集，表示一组散点数据。输入变量为 $x$，是一个 $8 \\times 1$ 的列向量；输出变量为 $y$，是对应的目标值。它们的关系即为我们要拟合的对象。\n",
    "\n",
    "$$\n",
    "x = \\begin{bmatrix}1 \\\\ 2 \\\\ 4 \\\\ 5 \\\\ 6 \\\\ 7 \\\\ 8 \\\\ 9 \\end{bmatrix}, \\quad\n",
    "y = \\begin{bmatrix}1 \\\\ 7 \\\\ 8 \\\\ 6 \\\\ 5 \\\\ 2 \\\\ 2 \\\\ 4 \\end{bmatrix}\n",
    "$$\n",
    "\n",
    "为了在一张图上画出平滑的回归曲线，代码使用 `np.linspace` 在区间 $[0, 10]$ 上生成了 101 个点构成的向量 $x_\\text{array}$，作为可视化时的横坐标。\n",
    "\n",
    "---\n",
    "\n",
    "### 一、设计矩阵构造\n",
    "\n",
    "为了进行三次多项式回归，代码根据变量 $x$ 构造了一个设计矩阵 $X_\\text{poly}$。该设计矩阵包含如下列：\n",
    "\n",
    "- 第1列：常数项 1，对应偏置 $b_0$\n",
    "- 第2列：$x$，对应一次项系数 $b_1$\n",
    "- 第3列：$x^2$，对应二次项系数 $b_2$\n",
    "- 第4列：$x^3$，对应三次项系数 $b_3$\n",
    "\n",
    "因此，设计矩阵的数学形式为：\n",
    "\n",
    "$$\n",
    "X = \n",
    "\\begin{bmatrix}\n",
    "1 & x_1 & x_1^2 & x_1^3 \\\\\n",
    "1 & x_2 & x_2^2 & x_2^3 \\\\\n",
    "\\vdots & \\vdots & \\vdots & \\vdots \\\\\n",
    "1 & x_n & x_n^2 & x_n^3 \\\\\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "其中 $n = 8$ 是样本个数。\n",
    "\n",
    "---\n",
    "\n",
    "### 二、最小二乘法求解参数\n",
    "\n",
    "代码使用正规方程（Normal Equation）求解最小二乘解：\n",
    "\n",
    "$$\n",
    "\\mathbf{b} = (X^\\top X)^{-1} X^\\top y\n",
    "$$\n",
    "\n",
    "向量 $\\mathbf{b}$ 为模型参数，包含了常数项 $b_0$ 和多项式系数 $b_1, b_2, b_3$，即：\n",
    "\n",
    "$$\n",
    "\\mathbf{b} = \n",
    "\\begin{bmatrix}\n",
    "b_0 \\\\\n",
    "b_1 \\\\\n",
    "b_2 \\\\\n",
    "b_3\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "---\n",
    "\n",
    "### 三、模型拟合与预测\n",
    "\n",
    "用训练集数据 $X_\\text{poly}$ 去预测回归值：\n",
    "\n",
    "$$\n",
    "\\hat{y} = X_\\text{poly} \\cdot \\mathbf{b}\n",
    "$$\n",
    "\n",
    "同时，为绘制回归曲线，需要对 101 个新的点 $x_\\text{array}$ 执行相同的特征扩展，并构造矩阵 $X_{\\text{array, poly}}$，结构与 $X_\\text{poly}$ 相同。然后执行：\n",
    "\n",
    "$$\n",
    "\\hat{y}_{\\text{array}} = X_{\\text{array, poly}} \\cdot \\mathbf{b}\n",
    "$$\n",
    "\n",
    "这样就得到一条连续平滑的回归曲线，用于图形展示。\n",
    "\n",
    "---\n",
    "\n",
    "### 四、图形可视化\n",
    "\n",
    "最后，代码使用 `matplotlib` 进行绘图，主要展示了三类内容：\n",
    "\n",
    "1. 原始数据点（蓝色叉号）\n",
    "2. 模型预测点 $\\hat{y}$（红色叉号）\n",
    "3. 真实值和预测值之间的误差线（黄色透明线段）\n",
    "\n",
    "此外，通过画出 $(x_\\text{array}, \\hat{y}_\\text{array})$ 的连续点连接线，得到红色的三次回归曲线。\n",
    "\n",
    "为了增强几何直观性，图像设置了相等比例，网格、坐标轴刻度均对称，确保读者能直观理解模型是如何拟合这些数据点的。\n",
    "\n",
    "---\n",
    "\n",
    "### 总结\n",
    "\n",
    "从数学视角看，这段代码通过将输入数据 $x$ 构造为多项式特征矩阵 $X$，并利用正规方程求解最小二乘解 $\\mathbf{b}$，实现了一个完整的三次多项式回归建模过程。其核心是把非线性的回归问题转化为线性模型在高维特征空间上的线性拟合过程。整个过程体现了**线性模型 + 非线性特征变换 = 非线性拟合能力**这一关键思想。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3755e7ba-2507-4703-9d28-dd14a8a662bb",
   "metadata": {},
   "source": [
    "## 初始化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d530bc5e-a5b5-41cf-92e4-461541be8fc2",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88bc42c5-5502-4a67-8b39-75438c34a6c6",
   "metadata": {},
   "source": [
    "## 构造数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "954b7525-dcef-47cb-af13-40c741ca3891",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = np.array([[1, 1],\n",
    "                 [2, 7],\n",
    "                 [4, 8],\n",
    "                 [5, 6],\n",
    "                 [6, 5],\n",
    "                 [7, 2],\n",
    "                 [8, 2],\n",
    "                 [9, 4]])\n",
    "x = data[:,[0]]\n",
    "y = data[:,[1]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "69c78d1a-fa1c-41cb-ae24-212360d40186",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 用于绘制回归曲线\n",
    "x_array = np.linspace(0,10,101).reshape(-1,1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee92efa0-9bf5-41e0-9628-30530a60fda2",
   "metadata": {},
   "source": [
    "## 设计矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "240a9861-c2b2-4aef-90b7-84daf99eec5b",
   "metadata": {},
   "outputs": [],
   "source": [
    "degree = 3 # 设定阶数\n",
    "\n",
    "# 增加不同阶数的数据\n",
    "X_poly = [x**d for d in range(1, degree + 1)]\n",
    "X_poly = np.hstack(X_poly)\n",
    "\n",
    "# 最左侧加一列全1\n",
    "X_poly = np.hstack([np.ones_like(x), X_poly])  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "a3c567f5-684f-4125-9a75-ad8b7ad7b4f4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  1,   1,   1,   1],\n",
       "       [  1,   2,   4,   8],\n",
       "       [  1,   4,  16,  64],\n",
       "       [  1,   5,  25, 125],\n",
       "       [  1,   6,  36, 216],\n",
       "       [  1,   7,  49, 343],\n",
       "       [  1,   8,  64, 512],\n",
       "       [  1,   9,  81, 729]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_poly"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b9d8f5d-f5ec-41b7-948f-6ad8a3110a9b",
   "metadata": {},
   "source": [
    "## 求解模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c21a6e8f-08f1-4537-99ee-1f2537ce2429",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-8.53960964],\n",
       "       [12.2117907 ],\n",
       "       [-2.64302613],\n",
       "       [ 0.16010855]])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.linalg.inv(X_poly.T @ X_poly) @ X_poly.T @ y\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "83c2895a-4514-4295-8f38-80823da9d0bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 提取参数\n",
    "coef = b[1:,:]\n",
    "intercept = b[0,:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "b636a5f4-0ad6-47ac-97e0-5043b6e38699",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-8.53960964])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "intercept"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "e1f86d7d-e112-4443-ab5b-9d495e3d505e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "12.211790696865584"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "coef[0][0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9a36e64-0b22-4798-91fd-a6f80acf9f55",
   "metadata": {},
   "source": [
    "## 拟合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "570ba0d7-380d-4333-a173-5ff1c9191dec",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.18926347],\n",
       "       [6.59273562],\n",
       "       [8.26608218],\n",
       "       [6.45725916],\n",
       "       [4.16564033],\n",
       "       [2.35187698],\n",
       "       [1.97662039],\n",
       "       [4.00052187]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_poly_pred = X_poly @ b\n",
    "y_poly_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "8dfb6461-55c0-4071-9626-fe6b79840289",
   "metadata": {},
   "outputs": [],
   "source": [
    "X_array_poly = [x_array**d for d in range(1, degree + 1)]\n",
    "X_array_poly = np.hstack(X_array_poly)\n",
    "X_array_poly = np.hstack([np.ones_like(x_array), X_array_poly])  # 最左侧加一列全1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "404b6b73-2604-44f1-9358-4765f34fc2d9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 多项式回归曲线纵轴预测值\n",
    "y_array_pred = X_array_poly @ b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a45dd7e3-1042-459c-b81d-e654748e07c7",
   "metadata": {},
   "source": [
    "## 可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "39e618c2-02a7-4d3b-8fe0-5efb4f24a68c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.0, 10.0)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAbkAAAHBCAYAAAD0JcWEAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABbfUlEQVR4nO3deVxU9f7H8dcwrLKpKAKCCu4huWSaZkmm5pJZttlipnmzstT8taktWKnZdq28abbYYqm31EpJ0xZQb1kumYSmFqhgKi7IpoIM5/fH12ERUJAznDPD5/l48JgzZ4Y570aaz3zP+S4WTdM0hBBCCBfkZnQAIYQQwlGkyAkhhHBZUuSEEEK4LClyQgghXJYUOSGEEC5LipwQQgiXJUVOCCGEy5IiJ4QQwmVJkRNCCOGypMgJl/Xhhx9isViKf7y9vQkJCeGaa65h5syZZGRkGB3R6Wzbto3BgwfTrFkzfHx8aNiwIT169GDhwoVGRxOiQu5GBxDC0RYsWEC7du04c+YMGRkZbNiwgVmzZvHqq6+yZMkS+vbta3REp3HixAkiIiK44447aNq0KXl5eXz66aeMGDGCvXv38vTTTxsdUYgyLDJ3pXBVH374IaNGjWLTpk107dq1zGP79++nV69enDhxgj179tCkSZNazXbq1Cl8fHxq9ZiOdMUVV/DPP/+wf/9+o6MIUYacrhR1UrNmzXjttdfIycnhnXfeKfPY5s2bueGGG2jYsCHe3t507tyZ//73v+VeY8OGDfTo0QNvb2+aNm3KM888w3vvvYfFYmHv3r3Fz2vRogXXX389y5Yto3Pnznh7ezNt2jQADh06xNixYwkPD8fT05PIyEimTZtGYWFhmWMVFBTw4osv0q5dO7y8vGjcuDGjRo3iyJEj+r85F6FRo0a4u8uJIWE+8lcp6qxBgwZhtVpZt25d8b4ff/yRAQMG0L17d+bNm0dgYCCLFy/m9ttv5+TJk9x7770AbN++nX79+tGmTRs++ugj6tWrx7x58yq9NrV161Z27tzJ008/TWRkJL6+vhw6dIhu3brh5ubGs88+S8uWLfn555958cUX2bt3LwsWLACgqKiIoUOHsn79ep544gl69uzJvn37eO6554iNjWXz5s3nbRVqmobNZqvSe1LVQlVUVERRURGZmZl8/vnnfPvtt8yZM6dKvytErdKEcFELFizQAG3Tpk2VPqdJkyZa+/bti++3a9dO69y5s3bmzJkyz7v++uu10NBQzWazaZqmabfeeqvm6+urHTlypPg5NptNu+SSSzRAS01NLd7fvHlzzWq1art27SrzmmPHjtX8/Py0ffv2ldn/6quvaoCWnJysaZqmLVq0SAO0pUuXlnnepk2bNEB7++23q/Q+VOWnqsaOHVv8O56enhfMIIRRpCUn6jSt1CXpv/76iz///JNXX30VoMwpw0GDBrFy5Up27dpF+/btSUxMpE+fPjRq1Kj4OW5ubtx2223ExcWVO86ll15KmzZtyuxbuXIl11xzDWFhYWWONXDgQB577DESExO55JJLWLlyJfXr12fIkCFlntepUydCQkJISEjgwQcfrPS/cciQIWzatKnqb0oVTJkyhTFjxpCRkcGKFSt4+OGHycvL47HHHtP1OELUlBQ5UWfl5eVx7NgxYmJiADh8+DAAjz32WKUf1kePHgXg2LFjFXZWqawDS2hoaLl9hw8fZsWKFXh4eJz3WIcPH+bEiRN4enqe93mVadiwIYGBged9TnU1a9aMZs2aAeoLAMDkyZMZOXIkjRs31vVYQtSEFDlRZ8XHx2Oz2YiNjQUobpVNnjyZYcOGVfg7bdu2BSAoKKi4KJZ26NChCn/PYrGU29eoUSMuvfRSpk+fXuHvhIWFFT8vKCiI1atXV/g8f3//CvfbffTRR4waNeq8z7HTLrKzdbdu3Zg3bx4pKSlS5ISpSJETddL+/ft57LHHCAwMZOzYsYAqYK1bt+b3339nxowZ5/393r17880333D06NHi4lhUVMTnn39e5QzXX38933zzDS1btqRBgwbnfd7ixYux2Wx07969yq9v54jTlef68ccfcXNzIyoqyqHHEaK6pMgJl/fHH39QWFhIYWEhGRkZrF+/ngULFmC1Wlm+fHmZlsc777zDwIEDue6667j33ntp2rQpx48fZ+fOnWzdurW4iE2dOpUVK1Zw7bXXMnXqVHx8fJg3bx55eXmAuj53Ic8//zxr166lZ8+ejB8/nrZt23L69Gn27t3LN998w7x58wgPD2f48OF8+umnDBo0iAkTJtCtWzc8PDxIT0/nxx9/ZOjQodx0002VHicoKIigoKAavovK/fffT0BAAN26daNJkyYcPXqUzz//nCVLlvD4449LK06Yj9E9X4RwlHN7FXp6emrB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",
      "text/plain": [
       "<Figure size 500x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots(figsize=(5,5))\n",
    "\n",
    "# 绘制散点图\n",
    "ax.scatter(x, y, marker = 'x', color = 'b')\n",
    "ax.scatter(x, y_poly_pred, marker = 'x', color='r')\n",
    "\n",
    "# 绘制误差\n",
    "data_ = np.column_stack([x,y_poly_pred])\n",
    "ax.plot(([i for (i,j) in data_], [i for (i,j) in data]),\n",
    "        ([j for (i,j) in data_], [j for (i,j) in data]),\n",
    "         c='#FFC000', alpha = 0.5)\n",
    "\n",
    "# 绘制回归曲线\n",
    "ax.plot(x_array, y_array_pred, color='r')\n",
    "ax.set_title('Degree = %d' % degree)\n",
    "\n",
    "ax.set_aspect('equal', adjustable='box')\n",
    "ax.set_xticks(np.arange(11))\n",
    "ax.set_yticks(np.arange(11))\n",
    "ax.set_xlim(0,10)\n",
    "ax.grid(True, c = '0.8')\n",
    "ax.set_ylim(0,10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf472ada-e959-49d0-961c-89d86f9bb868",
   "metadata": {},
   "source": [
    "## 回归解析式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "8fd12a6d-2ed5-42ac-a964-8e9f088e3ce3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "$y = -8.540 + 12.212x^1 -2.643x^2 + 0.160x^3$\n",
      "[[-8.53960964]\n",
      " [12.2117907 ]\n",
      " [-2.64302613]\n",
      " [ 0.16010855]]\n"
     ]
    }
   ],
   "source": [
    "equation = '$y = {:.3f}'.format(intercept[0])\n",
    "for j in range(0, len(coef[:,0])):\n",
    "    equation += ' + {:.3f}x^{}'.format(coef[j][0], j+1)\n",
    "equation += '$'\n",
    "equation = equation.replace(\"+ -\", \"-\")\n",
    "print(equation)\n",
    "print(str(b))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "070c3389-8048-43a3-baa7-6666009bce96",
   "metadata": {},
   "source": [
    "作者\t**生姜DrGinger**  \n",
    "脚本\t**生姜DrGinger**  \n",
    "视频\t**崔崔CuiCui**  \n",
    "开源资源\t[**GitHub**](https://github.com/Visualize-ML)  \n",
    "平台\t[**油管**](https://www.youtube.com/@DrGinger_Jiang)\t\t\n",
    "\t\t[**iris小课堂**](https://space.bilibili.com/3546865719052873)\t\t\n",
    "\t\t[**生姜DrGinger**](https://space.bilibili.com/513194466)  "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
